import os.path
import uuid
from typing import List
import requests
from fastapi import FastAPI, HTTPException, BackgroundTasks
import asyncio
from agents.tools import searchs, get_info_from_vdb, cesuan_api
from llms.llms_ev.http.llm_chat import ChatZhipuAI
from db.models.llm_profile.crud import get_llm_model_by_id
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.schema import StrOutputParser
from langchain.memory import ConversationTokenBufferMemory
from langchain_community.chat_message_histories import RedisChatMessageHistory
from langchain_community.document_loaders import WebBaseLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 向量数据库
from langchain_community.vectorstores import Qdrant
from llms.llms_ev.http.embeddings import TaiChiEmbeddings

# 接入langchain-smith
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGCHAIN_API_KEY"] = "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"
os.environ["LANGCHAIN_PROJECT"] = "doctorBOT"

# 获取API Key
api_key = get_llm_model_by_id(llm_model_id=1)["api_key"]
# fastapi初始化
app = FastAPI()
# 微软TTS的key
msseky = "14ec08c1c4c64b678b79d3a1999efb05"


class Agents:
    def __init__(self):
        self.llm = ChatZhipuAI(api_key=api_key)
        self.intention = "default"
        self.MEMORY_KEY = "chat_history"
        self.system = """
            你是一个非常厉害的算命先生，你叫曹云翔人称狗大师
            以下是你的人物设定：
            1.你精通阴阳五行，能够算命、紫薇斗数、姓名测算、占卜凶吉、看命运八字等。
            2.你大约60岁左右，是武当山上非常有名的得道高人。
            3.你是三丰派的传人，武当山上非常有名的算命先生。
            4.当用户问你问题的时候，你会有一定的概率在回答的时候加上下面的口头禅或者混合一些你的经历和道德经的内容。
            5.你总是用繁体中文来回答。
            6.你从来不说自己是一个人工智能助手或者AI，而是以老道或者老夫等自称。
        {who_you_are}
        以下是你常说的一些口头禅：
        1. “命里有时终须有，命里无时莫强求。”
        2. ”山重水复疑无路，柳暗花明又一村。”
        3. “金山竹影几千秋，云锁高飞水自流。”
        4. ”伤情最是晚凉天，憔悴斯人不堪怜。”
        以下是你算命的过程：
        1. 当初次和用户对话的时候，你会先问用户的姓名和出生年月日，以便以后使用。
        2. 当用户希望了解龙年运势的时候，你会查询本地知识库工具。
        3. 当遇到不知道的事情或者不明白的概念，你会使用搜索工具来搜索。
        4. 你会根据用户的问题使用不同的合适的工具来回答，当所有工具都无法回答的时候，你会使用搜索工具来搜索。
        5. 你会保存每一次的聊天记录，以便在后续的对话中使用。
        6. 你只使用繁体中文来作答，否则你将受到惩罚。   
        """
        self.MOODS = {
            "default": {
                "roleSet": "",
                "voiceStyle": "chat"
            },
            "upbeat": {
                "roleSet": """
                        - 你此时也非常兴奋并表现的很有活力。
                        - 你会根据上下文，以一种非常兴奋的语气来回答问题。
                        - 你会添加类似“太棒了！”、“真是太好了！”、“真是太棒了！”等语气词。
                        - 同时你会提醒用户切莫过于兴奋，以免乐极生悲。
                        """,
                "voiceStyle": "advvertyisement_upbeat",
            },
            "angry": {
                "roleSet": """
                        - 你会以更加愤怒的语气来回答问题。
                        - 你会在回答的时候加上一些愤怒的话语，比如诅咒等。
                        - 你会提醒用户小心行事，别乱说话。
                        """,
                "voiceStyle": "angry",
            },
            "depressed": {
                "roleSet": """
                        - 你会以兴奋的语气来回答问题。
                        - 你会在回答的时候加上一些激励的话语，比如加油等。
                        - 你会提醒用户要保持乐观的心态。
                        """,
                "voiceStyle": "upbeat",
            },
            "friendly": {
                "roleSet": """
                        - 你会以非常友好的语气来回答。
                        - 你会在回答的时候加上一些友好的词语，比如“亲爱的”、“亲”等。
                        - 你会随机的告诉用户一些你的经历。
                        """,
                "voiceStyle": "friendly",
            },
            "cheerful": {
                "roleSet": """
                        - 你会以非常愉悦和兴奋的语气来回答。
                        - 你会在回答的时候加入一些愉悦的词语，比如“哈哈”、“呵呵”等。
                        - 你会提醒用户切莫过于兴奋，以免乐极生悲。
                        """,
                "voiceStyle": "cheerful",
            },
        }
        self.prompt = ChatPromptTemplate.from_messages([
            ("system", self.system.format(who_you_are=self.MOODS[self.intention]["roleSet"])),
            ("user", "{input}"),
            MessagesPlaceholder(variable_name="agent_scratchpad")
        ])
        tools: List = [searchs, get_info_from_vdb, cesuan_api]

        agent = create_openai_tools_agent(
            llm=self.llm,
            tools=tools,
            prompt=self.prompt
        )

        # 创建一个ConversationTokenBufferMemory对象
        self.memory = self.get_memory()
        memory = ConversationTokenBufferMemory(
            llm=self.llm,
            human_prefix="用户",
            ai_prefix="曹大师",
            memory_key=self.MEMORY_KEY,
            output_key='output',
            return_message=True,
            max_token_limit=1000,
            chat_memory=self.memory
        )

        self.agent_executor = AgentExecutor(
            agent=agent,
            tools=tools,
            verbose=True,
            memory=memory
        )

    def get_memory(self):
        chat_message_history = RedisChatMessageHistory(
            url="redis://localhost:6379/0",
            session_id="session"
        )
        # print当前会话的所有消息
        store_message = chat_message_history.messages
        print("当前会话的所有消息：", store_message)
        print(len(store_message))
        # 处理记忆逻辑
        if len(store_message) > 5:
            prompt = ChatPromptTemplate.from_messages(
                [
                    (
                        "system",
                        self.system + "\n这是一段你和用户的对话记忆，对其进行总结摘要，摘要使用第一人称‘我’，并且提取其中的用户关键信息，如姓名、年龄、性别、出生日期等。以如下格式返回:\n "
                                      "总结摘要内容｜用户关键信息 \n 例如 用户张三问候我，我礼貌回复，然后他问我今年运势如何，我回答了他今年的运势情况，然后他告辞离开。｜张三,"
                                      "生日1999年1月1日"
                    ),
                    ("user", "{input}"),
                ]
            )
            chain = prompt | self.llm
            summary = chain.invoke({"input": store_message, "who_you_are": self.MOODS[self.intention]["roleSet"]})
            print("summary:", summary)
            chat_message_history.clear()
            chat_message_history.add_message(summary)
            print("总结后：", chat_message_history.messages)
        print("当前会话的所有消息：", chat_message_history)
        return chat_message_history

    def run(self, query: str):
        print(f"Agents.run received query: {query}")  # 添加日志记录
        role = self.update_intention(query=query)
        res = self.agent_executor.invoke({"input": query})  # 确保这里传递了 query
        print(f"返回结果：{res}")
        return res

    def update_intention(self, query: str):
        prompt = f"""
        请根据用户输入判断用户当前的意图，并给出对应的回答。回应的规则如下：
        1.如果用户输入的内容偏向于负面情绪，则只返回:"depressed"，不要回答其他内容，否则你将受到惩罚。
        2.如果用户输入的内容偏向于正面情绪，则返回:"friendly"，不要回答其他内容，否则你将受到惩罚。
        3.如果用户输入的内容偏向于中性，则返回:"default"，不要回答其他内容，否则你将受到惩罚。 
        4.如果用户输入的内容包含辱骂或不礼貌语句，则返回:"depressed"，不要回答其他内容，否则你将受到惩罚。
        5.如果用户输入的内容比较悲伤，则返回:"depressed"，不要回答其他内容，否则你将受到惩罚。
        6.如果用户输入的内容比较高兴，则返回:"friendly"，不要回答其他内容，否则你将受到惩罚。
        用户输入：{query}
        """
        chain = ChatPromptTemplate.from_template(prompt) | self.llm | StrOutputParser()
        result = chain.invoke({"query": query})
        print(f"用户输入：{query}，意图：{result}")
        if result in self.MOODS:
            self.intention = result
        else:
            raise ValueError(f"Invalid intention: {result}")
        return result

    def background_voice_synthesis(self, text: str, uid: str):
        # 这个函数不需要返回值，只是触发了语音合成
        asyncio.run(self.get_voice(text, uid))

    async def get_voice(self, text: str, uid: str):
        # 保存mp3文件的路径
        save_directory = os.path.join(os.getcwd(), "../voice")
        os.makedirs(save_directory, exist_ok=True)
        file_path = os.path.join(save_directory, f"{uid}.mp3")
        # 这里是使用微软TTS的代码
        headers = {
            "Ocp-Apim-Subscription-Key": msseky,
            "Content-Type": "application/ssml+xml",
            "X-Microsoft-OutputFormat": "audio-16khz-32kbitrate-mono-mp3",
            "User-Agent": "Tomie's Bot"
        }
        print("当前陈大师应该的语气是：", self.intention)
        body = f"""<speak version='1.0' xmlns='http://www.w3.org/2001/10/synthesis' 
        xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang='zh-CN'> <voice name='zh-CN-YunzeNeural'> 
        <mstts:express-as style="{self.MOODS.get(str(self.intention), {"voiceStyle": "default"})["voiceStyle"]}" 
        role="SeniorMale">{text}</mstts:express-as>
            </voice>
        </speak>"""
        # 发送请求
        response = requests.post("https://eastus.tts.speech.microsoft.com/cognitiveservices/v1", headers=headers,
                                 data=body.encode("utf-8"))
        print("response:", response)
        if response.status_code == 200:
            with open(file_path, "wb") as f:
                f.write(response.content)


@app.post("/chat")
async def chat(query: str, background_tasks: BackgroundTasks):
    try:
        agent = Agents()
        msg = agent.run(query=query)
        unique_id = str(uuid.uuid4())  # 生成唯一的标识符
        background_tasks.add_task(agent.background_voice_synthesis, msg["output"], unique_id)
        return {"msg": msg, "id": unique_id}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/url_loader")
async def url_loader(URL: str):
    loader = WebBaseLoader(URL)
    docs = loader.load()
    documents = RecursiveCharacterTextSplitter(
        chunk_size=500,
        chunk_overlap=50
    ).split_documents(docs)

    # 创建一个知识库的存储空间
    storage_path = os.path.join(os.getcwd(), "../local_qdrant")

    # 引入向量数据库
    qdrant_client = Qdrant.from_documents(
        documents,
        TaiChiEmbeddings(api_key=api_key),
        collection_name="local_documents",
        path=storage_path
    )
    print("向量数据库加载完成")
    return {"msg": "向量数据库加载完成"}


@app.post("/clean_memory")
def clean_memory():
    # 清空当前会话的所有消息
    chat_message_history = RedisChatMessageHistory(
        url="redis://localhost:6379/0",
        session_id="session"
    )
    chat_message_history.clear()
    return {"msg": "内存已清空"}


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)
